package com.xuz.singleton.demo04;

import com.xuz.singleton.demo03.Singleton_03;

/**
 * 单例模式 - 双重校验
 * 特点：支持延时加载，只有调用getInstance方法时，才会创建对象
 *      使用synchronized锁，锁住创建单例对象的方法，防止多个线程同时调用
 *      缺点：因为对getInstance() 方法加了锁，导致这个函数的并发度降低
 *
 * @user 65453
 * @date 2024/9/22 16:26
 */
public class Singleton_04 {
    // 1.构造一个私有方法
    private Singleton_04() {

    }

    //2.在本类中创建私有静态的全局对象
//    使用volatile保证变量可见性(该对象被线程修改后，别的线程会立即得到修改后的结果)；屏蔽指令重排序
    private volatile static Singleton_04 instance;

    //3.获取单例对象的静态方法
    public static Singleton_04 getInstance() {
        // 第一次判断对象是否被创建，不为null则不进入抢锁阶段，直接返回实例
        if (instance == null) {
            synchronized (Singleton_04.class) {
                // 第二次判断，抢到锁之后再次进行判断，判断是否为null
                if (instance == null) {
                    instance = new Singleton_04();
                    /**
                     * 上面创建对象的代码，在JVM中被分为三步
                     *      1.分配内存空间
                     *      2.初始化对象
                     *      3.将instance指向分配好的内存空间
                     *  但是JVM可能对上面的步骤进行指令重排序，就有可能变成  1，3，2
                     *  当执行完1，3后，此时instance不为空，那么别的线程进入该方法就会返回instance但此时的instance指向的内存空间并没有初始化对象
                     *  解决方法，添加volatile关键字
                     */
                }
            }
            instance = new Singleton_04();
        }
        return instance;
    }
}
